package org.mayanjun.code.easyweb.springmvc.controller;

import org.apache.commons.lang.StringUtils;
import org.mayanjun.code.easyweb.springmvc.config.Global;
import org.mayanjun.code.easyweb.springmvc.config.ServletApplicationConfig;
import org.mayanjun.code.easyweb.springmvc.handler.ApplicationExceptionHandler;
import org.mayanjun.code.easyweb.springmvc.view.SmartView;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.method.HandlerMethod;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;

/**
 * BaseController is used to be extended by any restful/page controller.
 * It provides an unified exception handler to handle all of the exceptions and returns a specified error page.
 * Not that please use @{@link RestController} to annotate controller if you are going to develop an restful controller,
 * otherwise your error message will not be converted to XML/JSON result.
 *
 * <p style="color:red">
 * TIPS: A controller should only be responsible for params checking and data binding.
 * </p>
 * 
 * @author mayanjun
 */
public abstract class BaseController {

	@ResponseBody
	@ExceptionHandler(Throwable.class)
	private Object handleException(Throwable t, HttpServletRequest request) {
		/**
		 * If this.class is annotated by @RestController
		 */
		if(isRestController()) {
			return ApplicationExceptionHandler.handleAllException(t);
		} else {
			/**
			 * If this.class is not annotated by @RestController but target method is annotated by @ResponseBody
			 */
			Object hmo = request.getAttribute(Global.REQUEST_ATTR_HANDLER_METHOD);
			if(hmo != null && hmo instanceof HandlerMethod) {
				HandlerMethod hm = (HandlerMethod) hmo;
				Method m = hm.getMethod();
				if(m != null && m.isAnnotationPresent(ResponseBody.class)) {
					return ApplicationExceptionHandler.handleAllException(t);
				}
			}
		}

		/**
		 * By default returns an SmartView
		 */
		return new SmartView(getErrorPage(request)).addObject(Global.ERROR_PAGE_KEY,
				ApplicationExceptionHandler.handleAllException(t));
	}

	private boolean isRestController() {
		Class<?> c = this.getClass();
		while (c != Object.class) {
			if(c.isAnnotationPresent(RestController.class)) return true;
			c = c.getSuperclass();
		}
		return false;
	}

	protected String getErrorPage(HttpServletRequest request) {
		String page = ServletApplicationConfig.getErrorPage();
		if(StringUtils.isNotBlank(page)) return page;
		return Global.DEFAULT_ERROR_PAGE;
	}

}
